package com.cy.pj.eiems.common.aspect;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.cy.pj.eiems.common.annotation.RequiredLog;
import com.cy.pj.eiems.common.util.IPUtils;
import com.cy.pj.eiems.entity.EiemsLog;
import com.cy.pj.eiems.service.EiemsLogService;

import lombok.extern.slf4j.Slf4j;


@Slf4j
@Aspect
@Component
public class EiemsLogAspect {
	@Pointcut("@annotation(com.cy.pj.eiems.common.annotation.RequiredLog)")
	public void logPointCut() {
	}

	@Around("logPointCut()")
	public Object aroundAdvice(ProceedingJoinPoint jp) throws Throwable {
		long start = System.currentTimeMillis();
		log.info("start: " + start);
		// 调用下一个切面或者目标方法
		Object result = jp.proceed();
		long end = System.currentTimeMillis();
		log.info("end: " + end);
		// 记录日志
		saveLog(jp, (end - start));
		return result;
	}

	@Autowired
	private EiemsLogService eiemsLogService;

	@Async
	private void saveLog(ProceedingJoinPoint jp, long time) throws Throwable {
		// 1.获取用户行为日志(ip,username,operation,method,params,time,createdTime)
		// 获取类的字节码对象，通过字节码对象获取方法信息
		Class<?> targetCls = jp.getTarget().getClass();
		// 获取方法签名(通过此签名获取目标方法信息)
		MethodSignature ms = (MethodSignature) jp.getSignature();
		// 获取目标方法上的注解指定的操作名称
		Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
		RequiredLog requiredLog = targetMethod.getAnnotation(RequiredLog.class);
		String operation = requiredLog.value();
		System.out.println("targetMethod=" + targetMethod);
		// 获取目标方法名(目标类型+方法名)
		String targetClsName = targetCls.getName();
		String targetObjectMethodName = targetClsName + "." + ms.getName();
		// 获取请求参数
		String targetMethodParams = Arrays.toString(jp.getArgs());
		// 2.封装用户行为日志(SysLog)
		EiemsLog entity = new EiemsLog();
		entity.setIp(IPUtils.getIpAddr());
		entity.setUsername("admin");
		entity.setOperation(operation);
		entity.setMethod(targetObjectMethodName);
		entity.setParams(targetMethodParams);
		entity.setTime(time);
		entity.setCreatedTime(new Date());
		// 3.调用业务层对象方法(saveObject)将日志写入到数据库
		eiemsLogService.saveObject(entity);
	}

}
